import QRCode from 'qrcode';
import { 
  PairingCode, 
  PairingRequest, 
  PairingData,
  SmartInputError,
  LogEntry,
  LogLevel 
} from '../types';
import { config, logConfig } from '../config';
import DeviceManager = require('./DeviceManager');

// 添加配对关系类型
interface PairingRelationship {
  id: string;
  device1Id: string;
  device2Id: string;
  device1Name: string;
  device2Name: string;
  device1Type: string;
  device2Type: string;
  createdAt: number;
  lastActivity: number;
  isActive: boolean;
}

class PairingManager {
  private pairingCodes: Map<string, PairingCode> = new Map();
  private pairingAttempts: Map<string, number> = new Map();
  private pairingRelationships: Map<string, PairingRelationship> = new Map();
  private cleanupInterval: NodeJS.Timeout;

  constructor(private deviceManager: DeviceManager) {
    // 定期清理过期的配对码和配对关系，并自动修复配对唯一性和脏数据
    this.cleanupInterval = setInterval(() => {
      this.cleanupExpiredCodes();
      this.cleanupExpiredPairings();
      this.autoRepairPairings(); // 新增：定期自动修复
    }, config.cleanup.pairingCodeCleanup);
  }

  /**
   * 生成配对码
   */
  async generatePairingCode(deviceId: string): Promise<{ code: string; qrCodeUrl: string; expiresAt: number }> {
    try {
      // 检查设备是否存在
      const device = this.deviceManager.getDevice(deviceId);
      if (!device) {
        throw new SmartInputError('Device not found', 'DEVICE_NOT_FOUND', 404);
      }

      // 在生成新码之前，先清理掉该设备所有旧的、未完成的配对码
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 为设备 ${deviceId} 生成新码前，清理旧码...`);
      }
      this.clearDevicePairingCodes(deviceId);

      // 如果是浏览器设备，实施唯一性控制
      if (device.type === 'browser') {
        this.enforceBrowserUniqueness(deviceId);
      }

      // 生成配对码
      const code = this.generateCode();
      const expiresAt = Date.now() + config.pairing.expirationTime;

      const pairingCode: PairingCode = {
        code,
        deviceId,
        expiresAt,
        isUsed: false
      };

      this.pairingCodes.set(code, pairingCode);

      // 生成QR码
      const qrData = JSON.stringify({
        type: 'smartinput_pairing',
        code,
        server: 'https://192.168.3.17:3001',
        timestamp: Date.now()
      });

      // 生成QR码数据URL
      const qrCodeUrl = await QRCode.toDataURL(qrData, {
        errorCorrectionLevel: 'M',
        width: 200,
        margin: 1,
        color: {
          dark: '#000000',
          light: '#FFFFFF'
        }
      });

      this.log('info', `配对码生成成功: ${code} for device ${deviceId}`, {
        deviceId,
        code,
        expiresAt
      });

      return { code, qrCodeUrl, expiresAt };
    } catch (error) {
      this.log('error', `配对码生成失败: ${error instanceof Error ? error.message : 'Unknown error'}`, {
        deviceId
      });
      throw error;
    }
  }

  /**
   * 使用配对码进行配对
   */
  async usePairingCode(code: string, requestingDeviceId: string): Promise<PairingData> {
    this.log('info', `[Pairing] 开始处理配对码: code=${code}, from=${requestingDeviceId}`);
    try {
      // 检查配对码是否存在
      const pairingCode = this.pairingCodes.get(code);
      if (!pairingCode) {
        this.log('warn', `[Pairing] 失败: 配对码不存在`, { code });
        throw new SmartInputError('Invalid pairing code', 'INVALID_PAIRING_CODE', 400);
      }
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 成功: 找到配对码`, { code, pairingCode });
      }

      // 检查配对码是否过期
      if (Date.now() > pairingCode.expiresAt) {
        this.pairingCodes.delete(code);
        this.log('warn', `[Pairing] 失败: 配对码已过期`, { code });
        throw new SmartInputError('Pairing code expired', 'PAIRING_CODE_EXPIRED', 400);
      }
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 成功: 配对码未过期`, { code });
      }

      // 检查配对码是否已使用
      if (pairingCode.isUsed) {
        this.log('warn', `[Pairing] 失败: 配对码已被使用`, { code });
        throw new SmartInputError('Pairing code already used', 'PAIRING_CODE_USED', 400);
      }
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 成功: 配对码尚未使用`, { code });
      }

      // 检查请求设备是否存在
      const requestingDevice = this.deviceManager.getDevice(requestingDeviceId);
      if (!requestingDevice) {
        this.log('error', `[Pairing] 失败: 发起配对的设备不存在`, { requestingDeviceId });
        throw new SmartInputError('Requesting device not found', 'REQUESTING_DEVICE_NOT_FOUND', 404);
      }
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 成功: 找到发起配对的设备`, { requestingDevice });
      }

      // 检查目标设备是否存在
      const targetDevice = this.deviceManager.getDevice(pairingCode.deviceId);
      if (!targetDevice) {
        this.pairingCodes.delete(code);
        this.log('error', `[Pairing] 失败: 目标设备不存在`, { targetDeviceId: pairingCode.deviceId });
        throw new SmartInputError('Target device not found', 'TARGET_DEVICE_NOT_FOUND', 404);
      }
      this.log('debug', `[Pairing] 成功: 找到目标设备`, { targetDevice });

      // 检查设备是否在线
      if (!this.deviceManager.isDeviceOnline(pairingCode.deviceId)) {
        this.log('warn', `[Pairing] 失败: 目标设备离线`, { targetDeviceId: pairingCode.deviceId });
        throw new SmartInputError('Target device is offline', 'TARGET_DEVICE_OFFLINE', 400);
      }
      this.log('debug', `[Pairing] 成功: 目标设备在线`, { targetDeviceId: pairingCode.deviceId });

      // 检查配对尝试次数
      const attemptKey = `${requestingDeviceId}:${code}`;
      const attempts = this.pairingAttempts.get(attemptKey) || 0;
      if (attempts >= config.pairing.maxAttempts) {
        this.log('warn', `[Pairing] 失败: 配对尝试次数过多`, { attemptKey });
        throw new SmartInputError('Too many pairing attempts', 'TOO_MANY_ATTEMPTS', 429);
      }
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 成功: 尝试次数检查通过`, { attempts });
      }

      // 增加尝试次数
      this.pairingAttempts.set(attemptKey, attempts + 1);

      // 标记配对码为已使用
      pairingCode.isUsed = true;
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 标记配对码为已使用`, { code });
      }

      // 移除配对码以防重复使用
      this.pairingCodes.delete(code);
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 删除已使用的配对码`, { code });
      }

      // 创建配对数据
      const pairingData: PairingData = {
        success: true,
        deviceId: pairingCode.deviceId,
        deviceName: targetDevice.name
      };

      // 创建配对关系前，先查找并失效同一对设备的旧活跃配对
      for (const [id, rel] of this.pairingRelationships.entries()) {
        if (
          rel.isActive &&
          ((rel.device1Id === requestingDeviceId && rel.device2Id === pairingCode.deviceId) ||
           (rel.device2Id === requestingDeviceId && rel.device1Id === pairingCode.deviceId))
        ) {
          rel.isActive = false;
          this.pairingRelationships.set(id, rel);
          this.log('info', `[去重] 失效旧配对关系: ${id}`, { id, device1Id: rel.device1Id, device2Id: rel.device2Id });
        }
      }
      // 创建配对关系
      const relationshipId = `pair_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
      const relationship: PairingRelationship = {
        id: relationshipId,
        device1Id: requestingDeviceId,
        device2Id: pairingCode.deviceId,
        device1Name: requestingDevice.name,
        device2Name: targetDevice.name,
        device1Type: requestingDevice.type,
        device2Type: targetDevice.type,
        createdAt: Date.now(),
        lastActivity: Date.now(),
        isActive: true
      };
      this.pairingRelationships.set(relationshipId, relationship);

      this.log('info', `配对成功: ${requestingDevice.name} (${requestingDeviceId}) <-> ${targetDevice.name} (${targetDevice.id})`, {
        requestingDeviceId,
        targetDeviceId: targetDevice.id,
        code,
        relationshipId
      });

      return pairingData;
    } catch (error) {
      this.log('error', `配对失败: ${error instanceof Error ? error.message : 'Unknown error'}`, {
        code,
        requestingDeviceId
      });
      throw error;
    }
  }

  /**
   * 验证配对码
   */
  validatePairingCode(code: string): boolean {
    const pairingCode = this.pairingCodes.get(code);
    if (!pairingCode) {
      return false;
    }

    if (Date.now() > pairingCode.expiresAt || pairingCode.isUsed) {
      this.pairingCodes.delete(code);
      return false;
    }

    return true;
  }

  /**
   * 获取配对码信息
   */
  getPairingCodeInfo(code: string): PairingCode | undefined {
    const pairingCode = this.pairingCodes.get(code);
    if (!pairingCode) {
      return undefined;
    }

    // 检查是否过期
    if (Date.now() > pairingCode.expiresAt) {
      this.pairingCodes.delete(code);
      return undefined;
    }

    return pairingCode;
  }

  /**
   * 清理指定设备的所有配对码
   */
  clearDevicePairingCodes(deviceId: string): void {
    const codesToDelete: string[] = [];
    
    // 找到所有属于该设备的配对码
    for (const [code, pairingCode] of this.pairingCodes) {
      if (pairingCode.deviceId === deviceId) {
        codesToDelete.push(code);
      }
    }
    
    // 删除找到的配对码
    codesToDelete.forEach(code => {
      this.pairingCodes.delete(code);
      if (logConfig.level === 'debug') {
        this.log('debug', `[Pairing] 清理设备配对码: ${code}`, { deviceId });
      }
    });
    
    if (codesToDelete.length > 0) {
      this.log('info', `[Pairing] 为设备 ${deviceId} 清理了 ${codesToDelete.length} 个旧配对码`);
    }
  }

  /**
   * 实施浏览器设备唯一性控制
   */
  private enforceBrowserUniqueness(currentDeviceId: string): void {
    const codesToDelete: string[] = [];
    const devicesToCleanup: string[] = [];
    
    // 检查设备ID模式，提取浏览器基础标识
    const baseBrowserId = this.extractBaseBrowserId(currentDeviceId);
    
    // 找到所有相关的浏览器设备和配对码
    for (const [code, pairingCode] of this.pairingCodes) {
      if (pairingCode.deviceId !== currentDeviceId) {
        const otherDevice = this.deviceManager.getDevice(pairingCode.deviceId);
        if (otherDevice && otherDevice.type === 'browser') {
          // 检查是否是同一浏览器的不同实例
          const otherBaseBrowserId = this.extractBaseBrowserId(pairingCode.deviceId);
          
          if (baseBrowserId && otherBaseBrowserId === baseBrowserId) {
            // 同一浏览器的不同实例，清理旧的
            codesToDelete.push(code);
            devicesToCleanup.push(pairingCode.deviceId);
            if (logConfig.level === 'debug') {
              this.log('debug', `[Browser Uniqueness] 发现同浏览器的旧实例: ${pairingCode.deviceId}`, { currentDeviceId });
            }
          } else if (!baseBrowserId) {
            // 无法识别浏览器基础ID，清理所有其他浏览器的配对码（原始逻辑）
            codesToDelete.push(code);
          }
        }
      }
    }
    
    // 删除找到的配对码
    codesToDelete.forEach(code => {
      this.pairingCodes.delete(code);
      if (logConfig.level === 'debug') {
        this.log('debug', `[Browser Uniqueness] 清理配对码: ${code}`, { currentDeviceId });
      }
    });
    
    // 标记旧的设备实例为离线（可选）
    devicesToCleanup.forEach(deviceId => {
      const device = this.deviceManager.getDevice(deviceId);
      if (device && device.isOnline) {
        // 这里可以标记设备为离线或清理，但要小心不要影响正在使用的连接
        if (logConfig.level === 'debug') {
          this.log('debug', `[Browser Uniqueness] 标记旧设备实例: ${deviceId}`, { currentDeviceId });
        }
      }
    });
    
    if (codesToDelete.length > 0) {
      this.log('info', `[Browser Uniqueness] 为浏览器设备 ${currentDeviceId} 实施唯一性控制，清理了 ${codesToDelete.length} 个配对码`);
    }
  }

  /**
   * 从设备ID中提取浏览器基础标识
   */
  private extractBaseBrowserId(deviceId: string): string | null {
    try {
      // 对于基于指纹的ID: browser_chrome_abc123def456
      const match = deviceId.match(/^browser_chrome_([a-z0-9]{12})$/);
      if (match && match[1]) {
        return match[1]; // 返回浏览器指纹ID
      }
      
      // 对于时间戳+随机数的旧格式，无法确定唯一性
      return null;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';
      if (logConfig.level === 'debug') {
        this.log('debug', `[Browser Uniqueness] 无法解析设备ID: ${deviceId}`, { error: errorMessage });
      }
      return null;
    }
  }

  /**
   * 获取统计信息
   */
  getStats() {
    const now = Date.now();
    const activeCodes = Array.from(this.pairingCodes.values()).filter(
      code => !code.isUsed && code.expiresAt > now
    );

    return {
      totalCodes: this.pairingCodes.size,
      activeCodes: activeCodes.length,
      usedCodes: Array.from(this.pairingCodes.values()).filter(code => code.isUsed).length,
      expiredCodes: Array.from(this.pairingCodes.values()).filter(
        code => !code.isUsed && code.expiresAt <= now
      ).length,
      activePairings: Array.from(this.pairingRelationships.values()).filter(r => r.isActive).length,
      totalPairings: this.pairingRelationships.size
    };
  }

  /**
   * 获取所有配对关系
   */
  getAllPairingRelationships(): PairingRelationship[] {
    return Array.from(this.pairingRelationships.values());
  }

  /**
   * 获取活跃的配对关系
   */
  getActivePairingRelationships(): PairingRelationship[] {
    return Array.from(this.pairingRelationships.values()).filter(r => r.isActive);
  }

  /**
   * 获取设备的配对关系
   */
  getDevicePairingRelationships(deviceId: string): PairingRelationship[] {
    return Array.from(this.pairingRelationships.values()).filter(
      r => r.isActive && (r.device1Id === deviceId || r.device2Id === deviceId)
    );
  }

  /**
   * 更新配对关系的活动时间
   */
  updatePairingActivity(device1Id: string, device2Id: string): void {
    for (const relationship of this.pairingRelationships.values()) {
      if (relationship.isActive && 
          ((relationship.device1Id === device1Id && relationship.device2Id === device2Id) ||
           (relationship.device1Id === device2Id && relationship.device2Id === device1Id))) {
        relationship.lastActivity = Date.now();
        break;
      }
    }
  }

  /**
   * 断开配对关系
   */
  disconnectPairing(device1Id: string, device2Id: string): boolean {
    for (const [id, relationship] of this.pairingRelationships) {
      if (relationship.isActive && 
          ((relationship.device1Id === device1Id && relationship.device2Id === device2Id) ||
           (relationship.device1Id === device2Id && relationship.device2Id === device1Id))) {
        relationship.isActive = false;
        this.log('info', `配对关系断开: ${relationship.device1Name} <-> ${relationship.device2Name}`, {
          relationshipId: id,
          device1Id,
          device2Id
        });
        return true;
      }
    }
    return false;
  }

  /**
   * 使指定设备的所有活跃配对关系失效
   */
  invalidatePairingsForDevice(deviceId: string): void {
    let count = 0;
    for (const [id, rel] of this.pairingRelationships.entries()) {
      if (rel.isActive && (rel.device1Id === deviceId || rel.device2Id === deviceId)) {
        rel.isActive = false;
        this.pairingRelationships.set(id, rel);
        count++;
        this.log('info', `[自动失效] 设备离线，失效配对关系: ${id}`, { id, device1Id: rel.device1Id, device2Id: rel.device2Id });
      }
    }
    if (count > 0) {
      this.log('info', `[自动失效] 设备 ${deviceId} 离线，失效配对关系共 ${count} 个`);
    }
  }

  /**
   * 自动修复配对唯一性、脏数据、离线宽限期等问题
   * 可定时调用，也可手动调用
   */
  public autoRepairPairings(): void {
    const now = Date.now();
    const activePairings = Array.from(this.pairingRelationships.values()).filter(r => r.isActive);
    const seenPairs = new Set<string>();
    let repairedCount = 0;
    let cleanedCount = 0;
    const offlineTimeout = config.pairing.offlineTimeout || 60000; // 默认60秒宽限期

    // 1. 修复同一对设备多条活跃配对，只保留最新一条
    // 按设备对分组，按创建时间降序
    const pairGroups: Record<string, PairingRelationship[]> = {};
    for (const rel of activePairings) {
      const key = [rel.device1Id, rel.device2Id].sort().join('__');
      if (!pairGroups[key]) pairGroups[key] = [];
      pairGroups[key].push(rel);
    }
    for (const group of Object.values(pairGroups)) {
      if (group.length > 1) {
        // 按创建时间降序，保留最新
        group.sort((a, b) => b.createdAt - a.createdAt);
        for (let i = 1; i < group.length; i++) {
          const item = group[i];
          if (item) {
            item.isActive = false;
            repairedCount++;
            this.log('info', `[自动修复] 失效多余配对: ${item.id}`, { id: item.id });
          }
        }
      }
    }

    // 2. 清理无效/脏配对（如设备已被删除、双方均离线超时、配对状态异常等）
    for (const [id, rel] of this.pairingRelationships.entries()) {
      // 设备不存在
      const dev1 = this.deviceManager.getDevice(rel.device1Id);
      const dev2 = this.deviceManager.getDevice(rel.device2Id);
      if (!dev1 || !dev2) {
        rel.isActive = false;
        cleanedCount++;
        this.log('info', `[自动修复] 失效无效配对: ${id}`, { id, reason: '设备不存在' });
        continue;
      }
      // 双方均离线且超时
      const lastSeen = Math.max(dev1.lastSeen || 0, dev2.lastSeen || 0);
      const bothOffline = !dev1.isOnline && !dev2.isOnline;
      if (rel.isActive && bothOffline && (now - lastSeen > offlineTimeout)) {
        rel.isActive = false;
        cleanedCount++;
        this.log('info', `[自动修复] 失效超时离线配对: ${id}`, { id, lastSeen, offlineFor: now - lastSeen });
      }
      // 配对状态异常
      if (typeof rel.isActive !== 'boolean') {
        rel.isActive = false;
        cleanedCount++;
        this.log('info', `[自动修复] 失效异常配对: ${id}`, { id, reason: 'isActive异常' });
      }
    }
    if (repairedCount > 0 || cleanedCount > 0) {
      this.log('info', `[自动修复] 修复多余配对${repairedCount}个，清理脏配对${cleanedCount}个`);
    }
  }

  /**
   * 生成随机配对码
   */
  private generateCode(): string {
    const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let result = '';
    
    for (let i = 0; i < config.pairing.codeLength; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    
    // 确保生成的码是唯一的
    if (this.pairingCodes.has(result)) {
      return this.generateCode();
    }
    
    return result;
  }

  /**
   * 清理过期的配对码
   */
  private cleanupExpiredCodes(): void {
    const now = Date.now();
    const codesToDelete: string[] = [];

    for (const [code, pairingCode] of this.pairingCodes.entries()) {
      if (now > pairingCode.expiresAt) {
        codesToDelete.push(code);
      }
    }

    for (const code of codesToDelete) {
      this.pairingCodes.delete(code);
    }

    if (codesToDelete.length > 0) {
      if (logConfig.level === 'debug') {
        this.log('debug', `清理过期配对码: ${codesToDelete.length} 个`);
      }
    }
  }

  /**
   * 清理配对尝试记录
   */
  private cleanupPairingAttempts(deviceId: string): void {
    const keysToDelete: string[] = [];
    
    for (const key of this.pairingAttempts.keys()) {
      if (key.startsWith(`${deviceId}:`)) {
        keysToDelete.push(key);
      }
    }

    for (const key of keysToDelete) {
      this.pairingAttempts.delete(key);
    }
  }

  /**
   * 清理过期的配对关系
   */
  private cleanupExpiredPairings(): void {
    const now = Date.now();
    const deviceTimeout = config.cleanup.deviceTimeout || 5 * 60 * 1000; // 5分钟
    for (const [id, relationship] of this.pairingRelationships) {
      if (relationship.isActive) {
        // 获取双方设备
        const dev1 = this.deviceManager.getDevice(relationship.device1Id);
        const dev2 = this.deviceManager.getDevice(relationship.device2Id);
        // 只有双方都存在且 lastSeen 均超时，才失效配对
        if (dev1 && dev2 && !dev1.isOnline && !dev2.isOnline &&
          (now - dev1.lastSeen > deviceTimeout) && (now - dev2.lastSeen > deviceTimeout)) {
          relationship.isActive = false;
          if (logConfig.level === 'debug') {
            this.log('debug', `配对关系因双方长时间离线而标记为非活跃: ${relationship.device1Name} <-> ${relationship.device2Name}`, {
              relationshipId: id,
              lastActivity: relationship.lastActivity,
              inactiveTime: now - relationship.lastActivity
            });
          }
        }
      }
    }
  }

  /**
   * 检查并自动恢复指定设备相关的失效配对关系（双方都在线时）
   */
  public tryRestorePairingsForDevice(deviceId: string): void {
    const now = Date.now();
    for (const rel of this.pairingRelationships.values()) {
      if (!rel.isActive && (rel.device1Id === deviceId || rel.device2Id === deviceId)) {
        const dev1 = this.deviceManager.getDevice(rel.device1Id);
        const dev2 = this.deviceManager.getDevice(rel.device2Id);
        if (dev1 && dev2 && this.deviceManager.isDeviceOnline(dev1.id) && this.deviceManager.isDeviceOnline(dev2.id)) {
          rel.isActive = true;
          rel.lastActivity = now;
          this.log('info', `[自动恢复] 恢复配对关系: ${rel.id}`, { id: rel.id, device1Id: rel.device1Id, device2Id: rel.device2Id });
        }
      }
    }
  }

  /**
   * 日志记录
   */
  private log(level: LogLevel, message: string, metadata?: Record<string, any>): void {
    const logEntry: LogEntry = {
      level,
      message,
      timestamp: Date.now(),
      metadata: metadata || undefined
    };

    console.log(`[${level.toUpperCase()}] ${message}`, metadata ? JSON.stringify(metadata) : '');
  }

  /**
   * 销毁管理器
   */
  destroy(): void {
    if (this.cleanupInterval) {
      clearInterval(this.cleanupInterval);
    }
    this.pairingCodes.clear();
    this.pairingAttempts.clear();
  }
}

export = PairingManager;
